﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VMS.FTS.APPPUSH.LETIDEVICES
{
    public class VMSImagePackage
    {
        DataInfo info;
        List<DataPackage> packages;
        public DataInfo Info
        {
            get
            {
                return info;
            }
            set
            {
                info = value;
            }
        }
        public List<DataPackage> Pakages
        {
            get
            {
                return packages;
            }
            set
            {
                packages = value;
            }
        }
        public VMSImagePackage(DataInfo ainfo, byte[] data)
        {

            Info = ainfo;
            packages = new List<DataPackage>();

            int dataLength = (int)CONST.DATA_PACKAGE_LENGTH - // total tcp package
                            DataPackage.HEADER_LENGTH - // header length
                            1; // CRC byte


            byte[] temp = new byte[dataLength];
            int nPackages = 0;
            if (data.Length % dataLength == 0)
                nPackages = data.Length / dataLength;
            else
                nPackages = data.Length / dataLength + 1;
            for (int i = 0, k = 0; i < nPackages - 1; i++, k += dataLength)
            {
                Array.Copy(data, k, temp, 0, dataLength);

                packages.Add(new DataPackage((ushort)i, temp));
            }

            int lastBufferSize = data.Length - (nPackages - 1) * dataLength;
            byte[] lastBuffer = new byte[lastBufferSize];
            if (lastBufferSize != 0)
            {
                Array.Copy(data, (nPackages - 1) * dataLength, lastBuffer, 0, lastBufferSize);
                packages.Add(new DataPackage((ushort)(nPackages - 1), lastBuffer));
            }

        }

        public static VMSImagePackage FromFileWithIndex(ushort index,string path)
        {
            Bitmap bitmap = null;
            try
            {
                bitmap = (Bitmap)Image.FromFile(path);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);

            }

            if (bitmap == null) return null;

            ushort BPP = 2;
            // create data info
            DataInfo info = new DataInfo(index,
                (ushort)bitmap.Width,
                (ushort)bitmap.Height, BPP);// 2 bit per pixel

            // alloc memory array
            BitArray bArray = new BitArray(bitmap.Width * bitmap.Height * BPP);
            // copy pixel from bitmap to led bit matrix
            for (int j = 0,k = 0; j < bitmap.Width; j++,k+=2)
            {
                for (int i = 0; i < bitmap.Height; i++)
                {
                    Color col = bitmap.GetPixel(j, i);
                    if (col.ToArgb() == Color.Red.ToArgb())
                    {
                        bArray[i * bitmap.Width * BPP + k] = true;
                        bArray[i * bitmap.Width * BPP + k + 1] = false;
                    }
                    else if (col.ToArgb() == Color.Lime.ToArgb())
                    {
                        bArray[i * bitmap.Width * BPP + k] = false;
                        bArray[i * bitmap.Width * BPP + k + 1] = true;
                    }
                    else if (col.ToArgb() == Color.Yellow.ToArgb())
                    {
                        bArray[i * bitmap.Width * BPP + k] = true;
                        bArray[i * bitmap.Width * BPP + k + 1] = true;
                    }
                    else
                    {
                        bArray[i * bitmap.Width * BPP + k] = false;
                        bArray[i * bitmap.Width * BPP + k + 1] = false;
                    }
                }
            }

            byte[] imageData = new byte[(bArray.Length +7)/ 8];
            // save as hex string
            bArray.CopyTo(imageData, 0);
                          
            return new VMSImagePackage(info, imageData);
        }
    }

    public class DataInfo
    {
        public ushort Index { get; set; }
        public ushort Width { get; set; }
        public ushort Height { get; set; }
        public ushort BPP { get; set; }// Bits per pixels
        //string version;
        //public string Version{get{return version;}}
        public DataInfo(ushort width, ushort height, ushort bpp)
        {
            Index = 1;
            Width = width;
            Height = height;
            BPP = bpp;
        }

        public DataInfo(ushort index, ushort width, ushort height, ushort bpp)
        {
            Index = index;
            Width = width;
            Height = height;
            BPP = bpp;
        }

        public byte[] Data
        {
            get
            {
                byte[] buffer = new byte[10];
                buffer[0] = (byte)COMMAND.SERVER_TAG;
                buffer[1] = (byte)COMMAND.DATA_INFO_HEADER;
                BitConverter.GetBytes(Index).CopyTo(buffer, 2);
                BitConverter.GetBytes(Width).CopyTo(buffer, 4);
                BitConverter.GetBytes(Height).CopyTo(buffer, 6);
                BitConverter.GetBytes(BPP).CopyTo(buffer, 8);
                return buffer;
            }
        }
    }

    public class DataPackage
    {
        public const ushort HEADER_LENGTH = sizeof(byte) + // sizeof ((byte)TAG.SERVER_TAG)
                                            sizeof(byte) + // sizeof ((byte)TAG.DATA_PACKAGE_HEADER)
                                            sizeof(ushort) + // size of id
                                            sizeof(ushort)   // size of length
                                            ;
        ushort ID;
        byte[] data;
        public DataPackage(ushort id, byte[] buffer)
        {
            ID = id;
            data = new byte[buffer.Length + HEADER_LENGTH];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.DATA_PACKAGE_HEADER;
            BitConverter.GetBytes(id).CopyTo(data, 2);
            BitConverter.GetBytes(((ushort)buffer.Length)).CopyTo(data, 4);
            buffer.CopyTo(data, 6);
        }

        public byte[] Data
        {
            get
            {
                return data;
            }
        }
    }

    public class FirmwareInfo
    {
        public ushort Version { get; set; }
        public int Count { get; set; }
        //string version;
        //public string Version{get{return version;}}
        public FirmwareInfo(ushort version, int count)
        {
            Version = version;
            Count = count;
            //version = iVersion;
        }

        public byte[] Data
        {
            get
            {
                byte[] buffer = new byte[8];
                buffer[0] = (byte)COMMAND.SERVER_TAG;
                buffer[1] = (byte)COMMAND.FIRMWARE_INFO_HEADER;
                BitConverter.GetBytes(Version).CopyTo(buffer, 2);
                BitConverter.GetBytes(Count).CopyTo(buffer, 4);
                //version.ToCharArray().CopyTo(buffer,9);
                //Array.Copy(version.ToCharArray(),0, buffer, 10, version.Length);
                return buffer;
            }
        }
    }

    public class FirmwarePackage
    {
        ushort ID;
        byte[] data;
        public static int HEADER_LENGTH = 6;
        public FirmwarePackage(ushort id, byte[] buffer)
        {
            if (buffer.Length != 512)
            {
                //Console.Write("\r Length: "+ buffer.Length);
            }
            ID = id;
            data = new byte[buffer.Length + HEADER_LENGTH];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.FIRMWARE_PACKAGE_HEADER;
            BitConverter.GetBytes(id).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)buffer.Length).CopyTo(data, 4);
            buffer.CopyTo(data, 6);
        }

        public byte[] Data
        {
            get
            {
                return data;
            }
        }
    }

    public class BlackboxFirmware
    {
        FirmwareInfo info;
        List<FirmwarePackage> packages;
        public FirmwareInfo Info
        {
            get
            {
                return info;
            }
            set
            {
                info = value;
            }
        }
        public List<FirmwarePackage> Pakages
        {
            get
            {
                return packages;
            }
            set
            {
                packages = value;
            }
        }
        public BlackboxFirmware(string path)
        {
            HexParser parser = new HexParser();
            parser.parse(path);
            //byte[] buffer = File.ReadAllBytes(path);
            //File.WriteAllBytes("C:\\out.txt", parser.data.ToArray());
            // Send Firmware Info
            info = new FirmwareInfo(101, parser.data.Length);

            packages = new List<FirmwarePackage>();

            int dataLength = (int)CONST.FIRMWARE_PACKAGE_LENGTH - // total tcp package
                            FirmwarePackage.HEADER_LENGTH - // header length
                            1; // CRC byte

            byte[] temp = new byte[dataLength];
            int nPackages = 0;
            if (parser.data.Length % dataLength == 0)
                nPackages = parser.data.Length / dataLength;
            else
                nPackages = parser.data.Length / dataLength + 1;

            for (int i = 0, k = 0; i < nPackages - 1; i++, k += dataLength)
            {
                Array.Copy(parser.data, k, temp, 0, dataLength); 

                packages.Add(new FirmwarePackage((ushort)i, temp));
            }

            int lastBufferSize = parser.data.Length - (nPackages - 1) * dataLength;
            byte[] lastBuffer = new byte[lastBufferSize];
            if (lastBufferSize != 0)
            {
                Array.Copy(parser.data, (nPackages - 1) * dataLength, lastBuffer, 0, lastBufferSize);
                packages.Add(new FirmwarePackage((ushort)(nPackages - 1), lastBuffer));
            }
        }

        class HexParser
        {
            List<byte> bytearray;
            int dataOffset;

            public byte[] data
            {
                get
                {
                    return bytearray.ToArray();
                }
            }
            public int Offset
            {
                get
                {
                    return dataOffset;
                }
            }
            public string parse(string filepath)
            {
                string strContent = "";
                string strConverted = "";
                dataOffset = -1;
                if (File.Exists(filepath))
                {
                    StreamReader hexReader = new StreamReader(filepath);

                    try
                    {
                        char startcode;
                        string temp = "";
                        int bytecount;
                        int address;
                        int recordtype;
                        string data;
                        int strLen = 0;
                        int unitLength = 0;
                        bytearray = new List<byte>();
                        do
                        {
                            strContent = hexReader.ReadLine();
                            strLen = strContent.Length;

                            //startcode = strContent.Substring(0,1);
                            bytecount = Convert.ToInt32(strContent.Substring(1, 2), 16);
                            address = Convert.ToInt32(strContent.Substring(3, 4), 16);
                            recordtype = Convert.ToInt32(strContent.Substring(7, 2), 16);

                            if (recordtype == 0)
                            {
                                if (dataOffset == -1)
                                {
                                    dataOffset = address;
                                }
                                data = strContent.Substring(9, strLen - 11);
                                if (bytecount != 0)
                                {
                                    unitLength = data.Length / bytecount;
                                    for (int i = 0; i < data.Length; i += unitLength)
                                    {
                                        temp = data.Substring(i, unitLength);
                                        byte value = Convert.ToByte(temp, 16);
                                        bytearray.Add(value);
                                    }

                                }
                            }
                        } while (hexReader.Peek() != -1);
                        /*
                        // Convert data to big endian order
                        byte tempLowbyte = 0;
                        byte tempHighbyte = 0;
                        for (int i = 0; i < bytearray.Count; i += 4)
                        {
                            tempLowbyte = bytearray[i + 3];
                            bytearray[i + 3] = bytearray[i];
                            bytearray[i] = tempLowbyte;

                            tempHighbyte = bytearray[i + 2];
                            bytearray[i + 2] = bytearray[i + 1];
                            bytearray[i + 1] = tempHighbyte;
                            /*
                            strConverted += bytearray[i].ToString() +
                                bytearray[i + 1].ToString() +
                                bytearray[i + 2].ToString() +
                                bytearray[i + 3].ToString() ;
                            if (i %2 != 0)
                            {
                                strConverted += " ";
                            }
                            else
                            {
                                strConverted += "\r\n";
                            }
                        }

                    */
                        return strConverted;
                    }
                    catch (Exception e)
                    {
                        strConverted += e.Message;
                    }
                }
                return strConverted;
            }
        }
    }

    public class FontInfo
    {
        public ushort ID { get; set; }
        public int DataSize { get; set; }
        
        public FontInfo(ushort version, int size)
        {
            ID = version;
            DataSize = size;
        }

        public byte[] Data
        {
            get
            {
                byte[] buffer = new byte[8];
                buffer[0] = (byte)COMMAND.SERVER_TAG;
                buffer[1] = (byte)COMMAND.FONT_INFO_HEADER;
                BitConverter.GetBytes(ID).CopyTo(buffer, 2);
                BitConverter.GetBytes(DataSize).CopyTo(buffer, 4);
                
                return buffer;
            }
        }
    }

    public class FontPackage
    {
        ushort ID;
        byte[] data;
        public const ushort HEADER_LENGTH = sizeof(byte) + // sizeof ((byte)TAG.SERVER_TAG)
                                            sizeof(byte) + // sizeof ((byte)TAG.DATA_PACKAGE_HEADER)
                                            sizeof(ushort) + // size of id
                                            sizeof(ushort)   // size of length
                                            ;
        public FontPackage(ushort id, byte[] buffer)
        {
            ID = id;
            data = new byte[buffer.Length + HEADER_LENGTH];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.FONT_PACKAGE_HEADER;
            BitConverter.GetBytes(id).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)buffer.Length).CopyTo(data, 4);
            buffer.CopyTo(data, 6);
        }

        public byte[] Data
        {
            get
            {
                return data;
            }
        }
    }

    public class FontFirmware
    {
        FontInfo info;
        List<FontPackage> packages;
        public FontInfo Info
        {
            get
            {
                return info;
            }
            set
            {
                info = value;
            }
        }
        public List<FontPackage> Pakages
        {
            get
            {
                return packages;
            }
            set
            {
                packages = value;
            }
        }
        public FontFirmware(string path)
        {
            // Load font info
            BinaryReader br = new BinaryReader(new FileStream(path, FileMode.Open));
            ushort fontID = br.ReadByte();
            int length = (int)(new FileInfo(path)).Length;
            info = new FontInfo(fontID, length);

            int dataLength = (int)CONST.FONT_PACKAGE_LENGTH - // total tcp package
                            FontPackage.HEADER_LENGTH - // header length
                            1; // CRC byte

            byte[] data = new byte[length];
            data[0] = (byte)fontID;
            br.ReadBytes(length - 1).CopyTo(data, 1);
            br.Close();
            packages = new List<FontPackage>();

            byte[] temp = new byte[dataLength];
            int nPackages = 0;
            if (length % dataLength == 0)
                nPackages = length / dataLength;
            else
                nPackages = length / dataLength + 1;

            for (int i = 0, k = 0; i < nPackages - 1; i++, k += dataLength)
            {
                Array.Copy(data, k, temp, 0, dataLength); 

                packages.Add(new FontPackage((ushort)i, temp));
            }

            int lastBufferSize = data.Length - (nPackages - 1) * dataLength;
            byte[] lastBuffer = new byte[lastBufferSize];
            if (lastBufferSize != 0)
            {
                Array.Copy(data, (nPackages - 1) * dataLength, lastBuffer, 0, lastBufferSize);
                packages.Add(new FontPackage((ushort)(nPackages - 1), lastBuffer));
            }
        }
    }
}
